.\"
.\" Copyright (C) 2017 by John Schember
.\" SPDX-License-Identifier: MIT
.\"
.TH ARES_LIBRARY_INIT_ANDROID 3 "13 Sept 2017"
.SH NAME
ares_library_init_android \- c-ares library Android initialization
.SH SYNOPSIS
.nf
#include <ares.h>

int ares_library_init_android(jobject \fIconnectivity_manager\fP)

int ares_library_android_initialized();

void ares_library_init_jvm(JavaVM *\fIjvm\fP)

.fi
.SH DESCRIPTION
The \fIares_library_init_android(3)\fP function performs initializations
internally required by the c-ares library when used on Android. This can take
place anytime after \fIares_library_init(3)\fP. It must take place after
\fIares_library_init_jvm\fP. ares_library_init_android must be called before
DNS resolution will work on Android 8 (Oreo) or newer when targetSdkVersion is
set to 26+.

As of Android 8 (API level 26) getting DNS server information has
becomei more restrictive and can only be accessed using the
Connectivity Manager. It is necessary to pass the connectivity
manager to c-ares via JNI. Also, the ACCESS_NETWORK_STATE permission
must be present in the Android application.

Android older than 8 do not need to to be initialized as they
are less restrictive. However, this is a run time not compile time
limitation. Proper Android initialization should take place regardless
of the targeted Android version.

Deinitialization will take place though \fIares_library_cleanup(3)\fP.

The \fBares_library_init_jvm\fP function allows the caller to register the JVM
with c-ares.  It's meant to be called during JNI_OnLoad because you're
guaranteed to have the JVM in that function. The JVM is required in order to
use the Connectivity Manager registered using
\fIares_library_init_android(3)\fP. This must be call before
\fIares_library_init_android(3)\fP.

The \fBares_library_android_initialized\fP function can be used to check
whether c-ares has been initialized for use with Android.
.SH RETURN VALUES
ARES_SUCCESS will be returned on success otherwise an error code will be
returned.
.SH THREAD SAFETY
.B These init functions are not thread safe.
You have to call it once the program has started, but this call must be done
before the program starts any other thread. This is required to avoid
potential race conditions in library initialization, and also due to the fact
these might call functions from other libraries that
are thread unsafe, and could conflict with any other thread that is already
using these other libraries.
.SH JNI
Accessing the Connectivity Manager though Java:

Register the \fIares_library_android_init\fP.
.nf
  static JNINativeMethod funcs[] = {
  { "initialize_native",     "(Landroid/net/ConnectivityManager;)I",
    (void *)&ares_library_init_android}
  };

  JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
  {
    JNIEnv *env = NULL;
    jclass  cls = NULL;
    jint    res;
  
    if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_6) != JNI_OK)
      return -1;
  
    cls = (*env)->FindClass(env, JNIT_CLASS);
    if (cls == NULL)
      return -1;
  
    res = (*env)->RegisterNatives(env, cls, funcs, sizeof(funcs)/sizeof(funcs[0]));
    if (res != 0)
      return -1;
  
    ares_library_init_jvm(vm);
    return JNI_VERSION_1_6;
  }
.fi
Calling the registered function from Java:
.nf
  public class MyObject {
    static {
      System.loadLibrary("cares");
    }
  
    private static native boolean initialize_native(ConnectivityManager
      connectivity_manager);
  
    public static boolean initialize(Context context) {
      initialize_native((ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE));
    }
  }
.fi
Initializing the Connectivity Manager in JNI directly using an Android
Context. It is assumed the JVM has already been registered through
\fIJNI_OnLoad\fP.
.nf
  void initialize(jobject android_context)
  {
    jclass obj_cls = jni_get_class(env, "android/content/Context");
    jmethodID obj_mid = jni_get_method_id(env, obj_cls, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
    jfieldID fid = (*env)->GetStaticFieldID(env, obj_cls, "CONNECTIVITY_SERVICE", "Ljava/lang/String;");
    jstring str = (*env)->GetStaticObjectField(env, obj_cls, fid);
    connectivity_manager = (*env)->CallObjectMethod(env, android_context, obj_mid, str);
    if (connectivity_manager == NULL)
      return;
    ares_library_init_android(connectivity_manager);
  }
.fi
.SH AVAILABILITY
This function was first introduced in c-ares version 1.15.0.
.SH SEE ALSO
.BR ares_library_init (3),
.BR ares_library_cleanup (3),

